package com.landinfo.web.rest;

import com.codahale.metrics.annotation.Timed;
import com.landinfo.domain.Region;
import com.landinfo.repository.RegionRepository;
import com.landinfo.service.dto.RegionDTO;
import com.landinfo.service.mapper.RegionMapper;
import com.landinfo.web.rest.util.HeaderUtil;
import com.landinfo.web.rest.util.PaginationUtil;
import io.github.jhipster.web.util.ResponseUtil;
import io.swagger.annotations.ApiParam;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * REST controller for managing Region.
 */
@RestController
@RequestMapping("/api")
public class RegionResource {

  private final Logger log = LoggerFactory.getLogger(RegionResource.class);

  private static final String ENTITY_NAME = "region";

  private final RegionRepository regionRepository;

  private final RegionMapper regionMapper;

  public RegionResource(RegionRepository regionRepository, RegionMapper regionMapper) {
    this.regionRepository = regionRepository;
    this.regionMapper = regionMapper;
  }

  /**
   * POST  /regions : Create a new region.
   *
   * @param regionDTO the regionDTO to create
   * @return the ResponseEntity with status 201 (Created) and with body the new regionDTO, or with status 400 (Bad Request) if the region has already an ID
   * @throws URISyntaxException if the Location URI syntax is incorrect
   */
  @PostMapping("/regions")
  @Timed
  public ResponseEntity<RegionDTO> createRegion(@RequestBody RegionDTO regionDTO) throws URISyntaxException {
    log.debug("REST request to save Region : {}", regionDTO);
    if (regionDTO.getId() != null) {
      return ResponseEntity.badRequest().headers(HeaderUtil.createFailureAlert(ENTITY_NAME, "idexists", "A new region cannot already have an ID")).body(null);
    }
    Region region = regionMapper.regionDTOToRegion(regionDTO);
    region = regionRepository.save(region);
    RegionDTO result = regionMapper.regionToRegionDTO(region);
    return ResponseEntity.created(new URI("/api/regions/" + result.getId()))
      .headers(HeaderUtil.createEntityCreationAlert(ENTITY_NAME, result.getId().toString()))
      .body(result);
  }

  /**
   * PUT  /regions : Updates an existing region.
   *
   * @param regionDTO the regionDTO to update
   * @return the ResponseEntity with status 200 (OK) and with body the updated regionDTO,
   * or with status 400 (Bad Request) if the regionDTO is not valid,
   * or with status 500 (Internal Server Error) if the regionDTO couldnt be updated
   * @throws URISyntaxException if the Location URI syntax is incorrect
   */
  @PutMapping("/regions")
  @Timed
  public ResponseEntity<RegionDTO> updateRegion(@RequestBody RegionDTO regionDTO) throws URISyntaxException {
    log.debug("REST request to update Region : {}", regionDTO);
    if (regionDTO.getId() == null) {
      return createRegion(regionDTO);
    }
    Region region = regionMapper.regionDTOToRegion(regionDTO);
    region = regionRepository.save(region);
    RegionDTO result = regionMapper.regionToRegionDTO(region);
    return ResponseEntity.ok()
      .headers(HeaderUtil.createEntityUpdateAlert(ENTITY_NAME, regionDTO.getId().toString()))
      .body(result);
  }

  /**
   * GET  /regions : get all the regions.
   *
   * @param pageable the pagination information
   * @return the ResponseEntity with status 200 (OK) and the list of regions in body
   * @throws URISyntaxException if there is an error to generate the pagination HTTP headers
   */
  @GetMapping("/regions")
  @Timed
  public ResponseEntity<List<RegionDTO>> getAllRegions(@ApiParam Pageable pageable) {
    log.debug("REST request to get a page of Regions");
    Page<Region> page = regionRepository.findAll(pageable);
    HttpHeaders headers = PaginationUtil.generatePaginationHttpHeaders(page, "/api/regions");
    return new ResponseEntity<>(regionMapper.regionsToRegionDTOs(page.getContent()), headers, HttpStatus.OK);
  }

  @PersistenceContext
  private EntityManager em;

  /**
   * get all the regions by id
   *
   * @param id
   * @return
   */
  @PostMapping("/regions/getChildren")
  @Timed
//  @Transactional
  @Cacheable(value = "RegionCache", key = "#id")
  public ResponseEntity<List<RegionDTO>> getAllRegions(@RequestBody String id) {

//    TypedQuery query = em.createQuery("select a from Region a where a.parentid = ?1", Region.class);
//    query.setParameter(1,id);
//    List<Region> page = regionRepository.findByWhere("parentid");

      List<Region> list = new ArrayList<>();// query.getResultList();
      Optional<Region> region = regionRepository.findById(id);
      region.ifPresent(list::add);
      return new ResponseEntity<>(regionMapper.regionsToRegionDTOs(list), HttpStatus.OK);
  }

  /**
   * get all the regions by id
   *
   * @param id
   * @return
   */
  @PostMapping("/regions/getChildren2")
  @Timed
  public ResponseEntity<List<RegionDTO>> getAllRegions2(@RequestBody String id) {
    //    String sql = String.format("WITH RECURSIVE r AS (SELECT * FROM public.t_region WHERE id = '%s'  union   ALL  SELECT t_region.* FROM public.t_region, r WHERE public.t_region.parentid = r.id ) SELECT * FROM r ORDER BY id;",id);
    String sql=String.format("select * from public.t_region WHERE id = '%s'",id);
    Query query = em.createNativeQuery(sql, Region.class);
    List<Region> userList = query.getResultList();
    em.close();
    return new ResponseEntity<>(regionMapper.regionsToRegionDTOs(userList), HttpStatus.OK);
  }

  /**
   * GET  /regions/:id : get the "id" region.
   *
   * @param id the id of the regionDTO to retrieve
   * @return the ResponseEntity with status 200 (OK) and with body the regionDTO, or with status 404 (Not Found)
   */
  @GetMapping("/regions/{id}")
  @Timed
  public ResponseEntity<RegionDTO> getRegion(@PathVariable String id) {
    log.debug("REST request to get Region : {}", id);
    Region region = regionRepository.findById(id).get();
    RegionDTO regionDTO = regionMapper.regionToRegionDTO(region);
    return ResponseUtil.wrapOrNotFound(Optional.ofNullable(regionDTO));
  }

  /**
   * DELETE  /regions/:id : delete the "id" region.
   *
   * @param id the id of the regionDTO to delete
   * @return the ResponseEntity with status 200 (OK)
   */
  @DeleteMapping("/regions/{id}")
  @Timed
  @CacheEvict(value = {"RegionCache"}, allEntries = true)
  public ResponseEntity<Void> deleteRegion(@PathVariable String id) {
    log.debug("REST request to delete Region : {}", id);
    regionRepository.deleteById(id);
    return ResponseEntity.ok().headers(HeaderUtil.createEntityDeletionAlert(ENTITY_NAME, id.toString())).build();
  }

}
